package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.exceptions.ForbiddenException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-12-07
 */
@Service
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    @Autowired
    private CourseClient courseClient;
    @Autowired
    private CatalogueClient catalogueClient;

    /**
     * 添加用户课程表--监听支付成功
     *
     * @param userId    用户id
     * @param courseIds 课程id集合
     */
    @Override
    public void addUserLessons(Long userId, List<Long> courseIds) {

        //feign调用查询课程信息,主要为了获取课程有效期
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(simpleInfoList)) {
            throw new IllegalArgumentException("课程不可用或不存在");
        }
        List<LearningLesson> learningLessons = new ArrayList<>();
        //遍历课程
        for (CourseSimpleInfoDTO course : simpleInfoList) {
            if (course.getValidDuration() != null && course.getValidDuration() > 0) {
                //构建课程表对象
                LearningLesson learningLesson = LearningLesson.builder()
                        .userId(userId)
                        .courseId(course.getId())
                        .createTime(LocalDateTime.now())
                        .expireTime(LocalDateTime.now().plusMonths(course.getValidDuration()))
                        .build();
                learningLessons.add(learningLesson);
            }
        }
        //插入数据库
        boolean b = saveBatch(learningLessons);
        if (!b) {
            throw new DbException("添加课程失败");
        }
    }


    /**
     * 分页查询课程表
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> queryLessonPage(PageQuery pageQuery) {
        if (pageQuery.getPageNo() == null || pageQuery.getPageSize() == null) {
            throw new IllegalArgumentException("分页参数不正确");
        }
        //获取当前用户id
        Long user = UserContext.getUser();
        if (user == null) {
            throw new IllegalArgumentException("用户未登录");
        }

        Page<LearningLesson> page = this.lambdaQuery().eq(LearningLesson::getUserId, user)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        //把page的records转成LearningLessonVO
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            log.warn("分页查询课程表为空");
            return PageDTO.empty(page);
        }
        //查询课程信息(封装到vo需要)
        Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);
        //封装vo
        List<LearningLessonVO> list = new ArrayList<>();
        for (LearningLesson record : records) {
            //转换vo
            LearningLessonVO learningLessonVO = BeanUtil.copyProperties(record, LearningLessonVO.class);
            CourseSimpleInfoDTO courseSimpleInfoDTO = cMap.get(record.getCourseId());
            learningLessonVO.setCourseName(courseSimpleInfoDTO.getName());
            learningLessonVO.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
            learningLessonVO.setSections(courseSimpleInfoDTO.getSectionNum());
            list.add(learningLessonVO);
        }

        return PageDTO.of(page, list);
    }

    /**
     * 查询课程信息map( 课程id : 课程信息)
     *
     * @param records
     * @return
     */
    private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {
        List<Long> idList = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(idList);
        if (CollUtils.isEmpty(simpleInfoList)) {
            throw new IllegalArgumentException("课程不存在或已过期");
        }
        return simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, v -> v));

    }


    /**
     * 查询正在学习的课程信息
     *
     * @return
     */
    @Override
    public LearningLessonVO queryNowLesson() {
        Long user = UserContext.getUser();
        if (UserContext.getUser() == null) {
            throw new IllegalArgumentException("用户未登录");
        }
        LearningLesson one = this.lambdaQuery().eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (one == null) {
            return null;
        }
        LearningLessonVO learningLessonVO = BeanUtil.copyProperties(one, LearningLessonVO.class);
        //查询课程信息
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(one.getCourseId(), false, false);
        if (courseInfo == null) {
            throw new IllegalArgumentException("课程不存在或已过期");
        }
        learningLessonVO.setCourseName(courseInfo.getName());
        learningLessonVO.setCourseCoverUrl(courseInfo.getCoverUrl());
        learningLessonVO.setSections(courseInfo.getSectionNum());
        //查询课表中课程总数
        Integer count = this.lambdaQuery().eq(LearningLesson::getUserId, user).count();
        learningLessonVO.setCourseAmount(count);
        //查询小节信息
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(CollUtils.singletonList(one.getCourseId()));
        if (CollUtils.isEmpty(cataSimpleInfoDTOS)) {
            throw new IllegalArgumentException("课程不存在或已过期");
        }
        CataSimpleInfoDTO cataSimpleInfoDTO = cataSimpleInfoDTOS.get(0);
        learningLessonVO.setLatestSectionName(cataSimpleInfoDTO.getName());
        learningLessonVO.setLatestSectionIndex(cataSimpleInfoDTO.getCIndex());

        return learningLessonVO;
    }

    /**
     * 根据课程id删除课程表记录
     *
     * @param courseId
     */
    @Override
    public void removeByCourseId(Long courseId) {
        if (courseId == null) {
            throw new ForbiddenException("参数错误");
        }
        boolean remove = this.lambdaUpdate()
                .eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .lt(LearningLesson::getExpireTime, LocalDateTime.now())
                .remove();
        if (!remove) {
            throw new DbException("删除失败");
        }
    }

    /**
     * 判断课程是否过期
     *
     * @param courseId
     * @return
     */
    @Override
    public Long isLessonValid(Long courseId) {
        Long user = UserContext.getUser();
        if (user == null) {
            throw new IllegalArgumentException("用户未登录");
        }
        LearningLesson one = this.lambdaQuery().eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
//        if (one!=null && one.getExpireTime().isAfter(LocalDateTime.now())){
//            return one.getId();
//        }
        if (one == null) {
            return null;
        }
        if (one.getExpireTime().isBefore(LocalDateTime.now())) {
            return null;
        }

        return one.getId();
    }

    /**
     * 查询课程状态
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonVO queryStatusByCourseId(Long courseId) {

        LearningLesson one = this.lambdaQuery().eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .last("limit 1")
                .one();
        if (one != null) {
            return BeanUtil.copyProperties(one, LearningLessonVO.class);
        }
        return null;
    }

    /**
     * 查询课程学习人数
     *
     * @param courseId
     * @return
     */
    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        return this.lambdaQuery().eq(LearningLesson::getCourseId, courseId).count();
    }

    /**
     * 创建学习计划
     */
    @Override
    public void createPlan(Long courseId, Integer freq) {
        if (courseId == null || freq == null) {
            throw new IllegalArgumentException("参数错误");
        }
        boolean update = this.lambdaUpdate().eq(LearningLesson::getUserId, UserContext.getUser())
                .eq(LearningLesson::getCourseId, courseId)
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING.getValue())
                .set(LearningLesson::getWeekFreq, freq)
                .update();
        if (!update) {
            throw new DbException("学习任务添加失败");
        }
    }

    @Autowired
    private LearningRecordMapper recordMapper;
    /**
     * 学习计划的分页查询
     *
     * @param pageQuery
     * @return
     */
    @Override
    public LearningPlanPageVO queryPlanPage(PageQuery pageQuery) {

        LearningPlanPageVO result = new LearningPlanPageVO();
        //获取当前用户Id
        Long userId = UserContext.getUser();
        //获取当前周
        LocalDate now = LocalDate.now();
        LocalDateTime begin = DateUtils.getWeekBeginTime(now);
        LocalDateTime end = DateUtils.getWeekEndTime(now);
        // 3.查询本周计划学习的所有课程，满足三个条件：属于当前用户、有学习计划、学习中
        List<LearningLesson> lessons = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING.getValue())
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .list();
        // 4.统计当前用户每个课程的已学习小节信息
        List<LearningRecord> learnedRecords = recordMapper.selectList(new QueryWrapper<LearningRecord>().lambda()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .gt(LearningRecord::getFinishTime, begin)
                .lt(LearningRecord::getFinishTime, end)
        );
        Map<Long, Long> countMap = learnedRecords.stream().collect(Collectors.groupingBy(LearningRecord::getLessonId, Collectors.counting()));
        // 5.查询总的统计数据
        // 5.1.本周总的已学习小节数量
        int weekFinished = learnedRecords.size();
        result.setWeekFinished(weekFinished);
        // 5.2.本周总的计划学习小节数量
        int weekTotalPlan = lessons.stream().mapToInt(LearningLesson::getWeekFreq).sum();
        result.setWeekTotalPlan(weekTotalPlan);
        // TODO 5.3.本周学习积分
        // 6.处理分页数据
        // 6.1.分页查询课表信息以及学习计划信息
        Page<LearningLesson> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize(), lessons.size());
        //这里是自己分页相当于把list集合分页了
        List<LearningLesson> records = CollUtils.sub(lessons, pageQuery.from(), pageQuery.from() + pageQuery.getPageSize());
        if (CollUtils.isEmpty(records)){
            //返回空页
            return result.emptyPage(page);
        }
        // 6.2.查询课表对应的课程信息
        Map<Long, CourseSimpleInfoDTO> cMap = queryCourseInfo(records);
        // 6.3.组装数据VO
        List<LearningPlanVO> voList = new ArrayList<>(records.size());
        for (LearningLesson record : records) {
            LearningPlanVO learningPlanVO = BeanUtils.copyProperties(record, LearningPlanVO.class);
            CourseSimpleInfoDTO courseSimpleInfoDTO = cMap.get(record.getCourseId());
            if (courseSimpleInfoDTO != null){
                learningPlanVO.setCourseName(courseSimpleInfoDTO.getName());
                learningPlanVO.setSections(courseSimpleInfoDTO.getSectionNum());
            }
            learningPlanVO.setWeekLearnedSections(countMap.getOrDefault(record.getId(),0L).intValue());

            voList.add(learningPlanVO);
        }

        return result.pageInfo(page.getTotal(), page.getPages(), voList);
    }

    /**
     * 查询课表对应的课程信息
     * @param records
     * @return
     */
    private Map<Long, CourseSimpleInfoDTO> queryCourseInfo(List<LearningLesson> records) {
        // 3.1.获取课程id
        Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        // 3.2.查询课程信息
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);
        if (CollUtils.isEmpty(cInfoList)) {
            // 课程不存在，无法添加
            throw new BadRequestException("课程信息不存在！");
        }
        return cInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, x->x));
    }
}
